home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 37 / Amiga Format CD37 (1999-02-16)(Future Publishing)(GB)(Track 1 of 3)[!][issue 1999-03].iso / -screenplay- / shareware / invasionforce / source / graphics.c < prev    next >
C/C++ Source or Header  |  1999-01-09  |  32KB  |  1,170 lines

  1. /*
  2.    graphics.c -- graphic functions module for Invasion Force
  3.  
  4.    This module provides graphics functions for the rest of the program,
  5.    especially map drawing and related functions for the map editor and
  6.    the game play modules.
  7.  
  8.    This source code is free.  You may make as many copies as you like.
  9. */
  10.  
  11. // standard header for all program modules
  12. #include "global.h"
  13.  
  14. #include <proto/layers.h>
  15. #include <graphics/gfxmacros.h>
  16.  
  17. USHORT __chip busy_pointer_data[] = {
  18.     0x0000, 0x0000,
  19.     0x0400, 0x07C0,
  20.     0x0000, 0x07C0,
  21.     0x0100, 0x0380,
  22.     0x0000, 0x07E0,
  23.     0x07C0, 0x1FF8,
  24.     0x1FF0, 0x3FEC,
  25.     0x3FF8, 0x7FDE,
  26.     0x3FF8, 0x7FBE,
  27.     0x7FFC, 0xFF7F,
  28.     0x7EFC, 0xFFFF,
  29.     0x7FFC, 0xFFFF,
  30.     0x3FF8, 0x7FFE,
  31.     0x3FF8, 0x7FFE,
  32.     0x1FF0, 0x3FFC,
  33.     0x07C0, 0x1FF8,
  34.     0x0000, 0x07E0,
  35.     0x0000, 0x0000
  36. }; // the data for a standard "busy" mouse pointer
  37.  
  38. /*
  39.    I store the map_window RastPort in here most of the time for handy
  40.    access by my functions, so I don't have to tell them what rastport to
  41.    use every time I call one of them.  And by changing this value I can
  42.    easily redirect all my graphics to another window for a while.
  43. */
  44. struct RastPort *rast_port = NULL;
  45.  
  46. // the bitmap where my map graphics are stored
  47. struct BitMap grafx_bitmap = { 0,0,0,0,0, 0,0,0,0, 0,0,0,0};
  48.  
  49. // single-hex tranfer bitmap and associated storage space
  50. struct BitMap hex_transfer;
  51. UBYTE __chip transfer_bitmap[512];
  52.  
  53.  
  54. // this stucture stores coordinates for plotting hexes
  55. struct hex_struct {
  56.    short srcx, srcy;
  57. } hexes[] = {
  58.    {0,65},     // unknown
  59.    {30,65},    // plains
  60.    {60,65},    // desert
  61.    {270,65},   // forbid
  62.    {180,65},   // brush
  63.    {210,65},   // forest
  64.    {240,65},   // jungle
  65.    {0,97},     // rugged
  66.    {30,97},    // hills
  67.    {60,97},    // mountains
  68.    {90,97},    // peaks
  69.    {120,97},   // swamp
  70.    {150,97},   // shallows
  71.    {180,97},   // ocean
  72.    {210,97},   // depth
  73.    {240,97}    // pack ice
  74. };
  75.  
  76. // this structure stores all the info I need to plot icons
  77. struct icon_struct {
  78.    short srcx, srcy;    // X,Y location on the map_grafx bitmap
  79.    ULONG *mask;         // my bit-mask for filling the player's color
  80. } icons[30];
  81.  
  82.  
  83. // the bitplane mask I use to blit hexagons onto the map
  84. ULONG __chip hex_mask[] = {
  85.    0x00000000,0x00010000,0x0007C000,0x001FF000,0x007FFC00,0x01FFFF00,
  86.    0x07FFFFC0,0x1FFFFFF0,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,
  87.    0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,
  88.    0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,0x7FFFFFFC,
  89.    0x7FFFFFFC,0x1FFFFFF0,0x07FFFFC0,0x01FFFF00,0x007FFC00,0x001FF000,
  90.    0x0007C000,0x00010000
  91. };
  92.  
  93. // the bitplane mask I use to put my "unit banned" icon on the screen
  94. ULONG __chip banned_mask[] = {
  95.    0x07F00000, 0x1C1C0000, 0x30060000, 0x600F0000, 0xC0398000,
  96.    0xC0618000, 0xC1C18000, 0xC3018000, 0xCE018000, 0x78030000,
  97.    0x30060000, 0x1C1C0000, 0x07F00000
  98. };
  99.  
  100. // here are my masks for blitting color fills onto icons
  101.    ULONG __chip battleship_mask[] = {
  102.       0xFFFFE000,0xFFBFE000,0xFF1FE000,0xFB0FE000,0xF807E000,
  103.       0xD803A000,0xC8012000,0xC8002000,0xC0002000,0xC0002000,
  104.       0xC0002000,0xC0002000,0xC0002000,0XE0002000,0XFFFFE000
  105.    };
  106.    ULONG __chip carrier_mask[] = {
  107.       0xFFFFE000,0xFFFFE000,0xFF3FE000,0xFE1FE000,0xFE1FE000,
  108.       0xFE0FE000,0xC0002000,0xC0002000,0xC0002000,0xC0002000,
  109.       0xC0002000,0xE0002000,0xE0002000,0xF0006000,0xFFFFE000
  110.    };
  111.    ULONG __chip cruiser_mask[] = {
  112.       0xFFFFE000,0xFFFFE000,0xFFBFE000,0xFF1FE000,0xF70EE000,
  113.       0xE2046000,0xE2046000,0xF000E000,0xC000E000,0xC0006000,
  114.       0xC0006000,0xE0006000,0xE0006000,0xF000E000,0xFFFFE000
  115.    };
  116.    ULONG __chip destroyer_mask[] = {
  117.       0xFFFFE000,0xFFFFE000,0xFFFFE000,0xFFFFE000,0xFF9FE000,
  118.       0xFF0FE000,0xFF03E000,0xFE01E000,0xE000E000,0xC0006000,
  119.       0xE0006000,0xF0006000,0xF8006000,0xFC00E000,0xFFFFE000
  120.    };
  121.    ULONG __chip sub_mask[] = {
  122.       0xFFFFE000,0xFFFFE000,0xFFFFE000,0xFFFFE000,0xFF3FE000,
  123.       0xFE1FE000,0xFE1FE000,0xFE0FE000,0xE0006000,0xC0002000,
  124.       0xC0002000,0xE0006000,0xFFFFE000,0xFFFFE000,0xFFFFE000
  125.    };
  126.    ULONG __chip transport_mask[] = {
  127.       0xFFFFE000,0xFF81E000,0xFF03E000,0xFE03E000,0xFC07E000,
  128.       0xF801E000,0xC0006000,0x80006000,0x80006000,0x80006000,
  129.       0xC0006000,0xE0006000,0xF0006000,0xF800E000,0xFFFFE000
  130.    };
  131.    ULONG __chip fighter_mask[] = {
  132.       0xFFFFE000,0xFFFFE000,0xFFE7E000,0xFFC3E000,0xFF876000,
  133.       0xFF062000,0xF8002000,0xE0002000,0xC0002000,0xE0002000,
  134.       0xFF062000,0xFF876000,0xFFC3E000,0xFFE7E000,0xFFFFE000
  135.    };
  136.    ULONG __chip armor_mask[] = {
  137.       0xFFFFE000,0xFFFFE000,0xFF83E000,0xE001E000,0xC000E000,
  138.       0xE000E000,0xFC00E000,0xC0006000,0x80002000,0x80002000,
  139.       0x80002000,0xC0006000,0xC0006000,0xE000E000,0xFFFFE000
  140.    };
  141.    ULONG __chip bomber_mask[] = {
  142.       0xFFFFE000,0xFE1FE000,0xFC0FE000,0xFC1E6000,0xFC0C2000,
  143.       0xC0002000,0x80002000,0x00002000,0x00002000,0x80002000,
  144.       0xFC1C2000,0xFC0E6000,0xFC1FE000,0xFE0FE000,0xFFFFE000
  145.    };
  146.    ULONG __chip aircav_mask[] = {
  147.       0xFFFFE000,0xFFFFE000,0xC002E000,0x80006000,0xC0002000,
  148.       0xE0002000,0xC0002000,0x80006000,0x0002E000,0x0007E000,
  149.       0x800FE000,0xC01FE000,0xC00FE000,0xE01FE000,0xFFFFE000
  150.    };
  151.    ULONG __chip rifle_mask[] = {
  152.       0xFFFFE000,0xF8FFE000,0xF07FE000,0xF03FE000,0xF001E000,
  153.       0xE000E000,0xE001E000,0xE00FE000,0xF07FE000,0xF07FE000,
  154.       0xF03FE000,0xF03FE000,0xF03FE000,0xF01FE000,0xFFFFE000
  155.    };
  156.    ULONG __chip city_mask[] = {
  157.       0x31830000,0x31830000,0xFFFF0000,0xFFFF0000,0x318F0000,
  158.       0x318F0000,0x319B8000,0x319B8000,0xFFB30000,0xFFB30000,
  159.       0x31E30000,0x31E30000,0xFFFF8000,0xFFFF8000,0x31E30000
  160.    };
  161.    ULONG __chip airbase_mask[] = {
  162.       0xFE7FE000,
  163.       0xC0302000,
  164.       0x80602000,
  165.       0x80C06000,
  166.       0x0080E000,
  167.       0x8001E000,
  168.       0xC403E000,
  169.       0xEC06E000,
  170.       0xF8046000,
  171.       0xF0002000,
  172.       0xE0200000,
  173.       0xC0602000,
  174.       0x80C02000,
  175.       0x81806000,
  176.       0xFFCFE000
  177.    };
  178.  
  179.  
  180. // These are masks for blitting land and sea mines onto the screen.
  181.    ULONG __chip landmine_mask[] = {
  182.       0x0F000000, 0x3FC00000, 0x3FC00000, 0xFFF00000,
  183.       0xFFF00000, 0xFFF00000, 0x1F800000, 0x00000000
  184.    };
  185.    ULONG __chip seamine_mask[] = {
  186.       0x77000000, 0xFF800000, 0xFF800000, 0xFF800000, 0x7F000000,
  187.       0xFF800000, 0xFF800000, 0xFF800000, 0x77000000, 0x00000000
  188.    };
  189. //
  190.  
  191. // region for my map-clipping rectangle
  192. struct Region *map_region = NULL;
  193. struct Region *bar_region = NULL;
  194.  
  195. void init_icons()
  196. {  // link all the icons to their proper bit-masks
  197.    icons[BATTLESHIP].srcx = 1;
  198.    icons[BATTLESHIP].srcy = 49;
  199.    icons[BATTLESHIP].mask = battleship_mask;
  200.  
  201.    icons[CARRIER].srcx = 23;
  202.    icons[CARRIER].srcy = 49;
  203.    icons[CARRIER].mask = carrier_mask;
  204.  
  205.    icons[CRUISER].srcx = 45;
  206.    icons[CRUISER].srcy = 49;
  207.    icons[CRUISER].mask = cruiser_mask;
  208.  
  209.    icons[DESTROYER].srcx = 67;
  210.    icons[DESTROYER].srcy = 49;
  211.    icons[DESTROYER].mask = destroyer_mask;
  212.  
  213.    icons[SUB].srcx = 89;
  214.    icons[SUB].srcy = 49;
  215.    icons[SUB].mask = sub_mask;
  216.  
  217.    icons[TRANSPORT].srcx = 111;
  218.    icons[TRANSPORT].srcy = 49;
  219.    icons[TRANSPORT].mask = transport_mask;
  220.  
  221.    icons[FIGHTER].srcx = 133;
  222.    icons[FIGHTER].srcy = 49;
  223.    icons[FIGHTER].mask = fighter_mask;
  224.  
  225.    icons[ARMOR].srcx = 155;
  226.    icons[ARMOR].srcy = 49;
  227.    icons[ARMOR].mask = armor_mask;
  228.  
  229.    icons[BOMBER].srcx = 199;
  230.    icons[BOMBER].srcy = 49;
  231.    icons[BOMBER].mask = bomber_mask;
  232.  
  233.    icons[AIRCAV].srcx = 221;
  234.    icons[AIRCAV].srcy = 49;
  235.    icons[AIRCAV].mask = aircav_mask;
  236.  
  237.    icons[RIFLE].srcx = 265;
  238.    icons[RIFLE].srcy = 49;
  239.    icons[RIFLE].mask = rifle_mask;
  240.  
  241.    icons[CITY].srcx = 287;
  242.    icons[CITY].srcy = 49;
  243.    icons[CITY].mask = city_mask;
  244.  
  245.    icons[AIRBASE].srcx = 177;
  246.    icons[AIRBASE].srcy = 49;
  247.    icons[AIRBASE].mask = airbase_mask;
  248. }
  249.  
  250. /*
  251.    NOTE: All the graphics functions that use raw, pixelwise coordinates
  252.    have names beginning with "px_".  This distinguishes them from the
  253.    higher level functions that go by row and column.
  254. */
  255.  
  256. // draw a hex cell outline, pixelwise, current color
  257. void px_outline_hex(x,y)
  258. int x,y;
  259. {
  260.    Move(rast_port,x+15,y);
  261.    Draw(rast_port,x,y+8);
  262.    Draw(rast_port,x,y+24);
  263.    Draw(rast_port,x+15,y+32);
  264.    Draw(rast_port,x+30,y+24);
  265.    Draw(rast_port,x+30,y+8);
  266.    Draw(rast_port,x+15,y);
  267. }
  268.  
  269.  
  270. // macro fills in a hex, current color, no outline
  271. #define px_wipe_hex(a,b) BltPattern(rast_port,(PLANEPTR)hex_mask,a,b,a+30,b+31,4);
  272.  
  273.  
  274. void px_plot_hex(destx,desty,code)
  275. int destx,desty,code;
  276. {  // plot a map terrain hex at the specified X,Y pixel coords
  277.    BltBitMap(&grafx_bitmap,hexes[code].srcx,hexes[code].srcy,&hex_transfer,0,0,32,32,0x0C0,0xFF,NULL);
  278.    BltMaskBitMapRastPort(&hex_transfer,0,0,rast_port,destx,desty,32,32,0xE0,(PLANEPTR)hex_mask);
  279. }
  280.  
  281.  
  282. /*
  283.    wrap_coords() takes a pair of coordinates that may be somewhere off the map
  284.    and wraps them around onto it.  The end result is a pair of coordinates that
  285.    are definitely somewhere on the map.  This only works currently with the
  286.    wrap-around map option (because otherwise we should never be dealing with
  287.    coords off the map).  It is always safe to call.
  288. */
  289.  
  290. void wrap_coords(col,row)
  291. int *col, *row;
  292. {  // correct the coordinates for a wrap-around map
  293.    if (wrap) {
  294.       while (*col<0)
  295.          *col += width;
  296.       while (*col>=width)
  297.          *col -= width;
  298.       while (*row<0)
  299.          *row += height;
  300.       while (*row>=height)
  301.          *row -= height;
  302.    FI
  303. }
  304.  
  305.  
  306. /*
  307.    The log_to_abs() function is critical for the graphics subsystems.
  308.    It takes a LOGICAL col,row coordinate pair specifying a map sector,
  309.    and translates that to an ABSOLUTE pixel location on the screen,
  310.    taking into account the current offset values, wrap-around, etc.
  311.    This function is not responsible for clipping -- the new *absx and
  312.    *absy values may or may not actually be somewhere on the screen.
  313.  
  314.    This function assumes we are dealing with hexagons.  Unit icons will
  315.    require an additional offset to center them in the hex.
  316.  
  317.    For the reverse of this function, see abs_to_log().
  318.    See also log_to_phys(), which converts logical coords to a physical sector
  319.    location on the screen display.
  320. */
  321.  
  322. void log_to_abs(col,row,absx,absy)
  323. int col, row, *absx, *absy;
  324. {
  325.    int phx, phy;     // physical sector coordinates
  326.  
  327.    *absx = -100;
  328.    *absy = -100;
  329.  
  330.    phx = col-xoffs;
  331.    phy = row-yoffs;
  332.    if (wrap) {
  333.       if (phx<-1)
  334.          phx += width;
  335.       if (phx>disp_wd)
  336.          phx -= width;
  337.       if (phy<-1)
  338.          phy += height;
  339.       if (phy>disp_ht)
  340.          phy -= height;
  341.    FI
  342.    if (phx<-1 || phx>disp_wd || phy<-1 || phy>disp_ht)
  343.       return;
  344.    /*
  345.       I use a "neatness" border of 4 or 6 pixels at the top & left edges
  346.       That includes the visible beveled border plus a little extra space
  347.       also +10 x to make room for the movement bar meter
  348.    */
  349.    *absx = map_window->BorderLeft+6+phx*30+abs(15*(row%2))+10;
  350.    *absy = map_window->BorderTop+4+phy*24;
  351. }
  352.  
  353.  
  354. /*
  355.    given an x/y pixel location, find the hex cell that is under it
  356.    this returns the position on the MAP, not the display
  357.    i.e. the values are corrected for offset
  358.    for the opposite conversion, see log_to_abs()
  359.    see also log_to_phys()
  360.    NOTE: This function can accept coordinates way off the actual display.
  361. */
  362. void abs_to_log(px,py,col,row)
  363. int px, py, *col, *row;
  364. {
  365.    *row = yoffs+(py-1)/24-1;
  366.    *col = xoffs+((px+19)-((*row%2)*15)-10)/30-1; // -10 x for movement bar
  367.  
  368.    if (wrap) {
  369.       if (*col<0)
  370.          *col += width;
  371.       if (*col>width)
  372.          *col -= width;
  373.       if (*row<0)
  374.          *row += height;
  375.       if (*row>height)
  376.          *row -= height;
  377.    }
  378. }
  379.  
  380.  
  381. /*
  382.    log_to_phys() converts a set of logical (map) coordinates to a physical
  383.    sector location relative the map display.  THE RESULTING SECTOR COORDINATES
  384.    MAY OR MAY NOT ACTUALLY BE ON THE SCREEN!!!  This is a low level routine
  385.    meant to be used by visibleP(), log_to_abs(), and related functions.
  386. */
  387. void log_to_phys(col,row,phx,phy)
  388. int col, row, *phx, *phy;
  389. {
  390.    wrap_coords(&col,&row);
  391.    *phx = col-xoffs;
  392.    *phy = row-yoffs;
  393.    if (wrap) {
  394.       if (*phx<0)
  395.          *phx += width;
  396.       if (*phx>disp_wd)
  397.          *phx -= width;
  398.       if (*phy<0)
  399.          *phy += height;
  400.       if (*phy>disp_ht)
  401.          *phy -= height;
  402.    FI
  403. }
  404.  
  405.  
  406. void outline_hex(col,row,color)
  407. int col,row,color;
  408. {  // outline (highlight) a hex with the specified color
  409.    int px, py;
  410.  
  411.    log_to_abs(col,row,&px,&py);
  412.    SetAPen(rast_port,color);
  413.    px_outline_hex(px,py);
  414. }
  415.  
  416.  
  417. void wipe_hex(col,row,color)
  418. int col,row,color;
  419. {  // solid-fill a hex with the specified color
  420.    int px, py;
  421.  
  422.    log_to_abs(col,row,&px,&py);
  423.    SetAPen(rast_port,color);
  424.    px_outline_hex(px,py);
  425.    px_wipe_hex(px,py);
  426. }
  427.  
  428.  
  429. void plot_hex(col,row,code)
  430. int col,row,code;
  431. {  // plot a terrain hex at a specified column and row
  432.    int px, py;
  433.  
  434.    log_to_abs(col,row,&px,&py);
  435.  
  436.    // outline the hex in black
  437.    SetAPen(rast_port,BLACK);
  438.    px_outline_hex(px,py);
  439.  
  440.    // copy graphics to "hex_transfer" bitmap area
  441.    BltBitMap(&grafx_bitmap,hexes[code].srcx,hexes[code].srcy,&hex_transfer,0,0,32,32,0x0C0,0xFF,NULL);
  442.  
  443.    // blit onto the screen using the hexagon mask
  444.    BltMaskBitMapRastPort(&hex_transfer,0,0,rast_port,px,py,32,32,0xE0,(PLANEPTR)hex_mask);
  445. }
  446.  
  447.  
  448. void drawto(x1,y1,x2,y2,color)
  449. int x1,y1,x2,y2,color;
  450. {
  451.    SetAPen(rast_port,color);
  452.    Move(rast_port,x1,y1);
  453.    Draw(rast_port,x2,y2);
  454. }
  455.  
  456.  
  457. void draw_road(col1,row1,col2,row2)
  458. int col1, row1, col2, row2;
  459. {
  460.    int x1, y1, x2, y2;
  461.    int cx, cy;
  462.  
  463.    if (!(visibleP(col1,row1)&&visibleP(col2,row2)))
  464.       return;
  465.  
  466.    log_to_abs(col1,row1,&x1,&y1);
  467.    log_to_abs(col2,row2,&x2,&y2);
  468.  
  469.    x1+=15; y1+=16; x2+=15; y2+=16;
  470.  
  471.    if (row1==row2)
  472.       for (cy=-2; cy<=3; cy++)
  473.          drawto(x1,y1+cy,x2,y2+cy,BLACK);
  474.    else
  475.       for (cx=-2; cx<=2; cx++)
  476.          for (cy=-1; cy<=1; cy++)
  477.             drawto(x1+cx,y1+cy,x2+cx,y2+cy,BLACK);
  478.  
  479.    SetDrPt(rast_port,0x1F1F);
  480.    SetBPen(rast_port,BLACK);
  481.    drawto(x1,y1,x2,y2,WHITE);
  482.    SetBPen(rast_port,LT_GRAY);
  483.    SetDrPt(rast_port,(unsigned short)~0);
  484. }
  485.  
  486. #if FALSE
  487. // draws all roads going out from a given hex
  488. // used mainly for map editor display
  489.  
  490. void hex_draw_roads(col,row)
  491. int col, row;
  492. {
  493.    int hexes, ctr, flag;
  494.  
  495.    // outline_hex(col,row,WHITE);
  496.    hexes = adjacent(col,row);
  497.    for (ctr=0; ctr<hexes; ctr++) {
  498.       flag = get_flags(t_grid,hexlist[ctr].col,hexlist[ctr].row);
  499.       if (flag & ROAD)
  500.          draw_road(col,row,hexlist[ctr].col,hexlist[ctr].row);
  501.    OD
  502. }
  503.  
  504.  
  505. // Following is same as hex_draw_roads(), except specific to the
  506. // current player.  (i.e. only draws roads he knows about)
  507.  
  508. void plex_draw_roads(col,row)
  509. int col, row;
  510. {
  511.    int hexes, ctr, flag;
  512.  
  513.    // outline_hex(col,row,WHITE);
  514.    hexes = adjacent(col,row);
  515.    for (ctr=0; ctr<hexes; ctr++) {
  516.       flag = get_flags(PLAYER.map,hexlist[ctr].col,hexlist[ctr].row);
  517.       if (flag & ROAD)
  518.          draw_road(col,row,hexlist[ctr].col,hexlist[ctr].row);
  519.    OD
  520. }
  521. #endif
  522.  
  523. // draw a 3-D look beveled box, as around an icon
  524.  
  525. void bevel_box(x,y,w,h,depress)
  526. int x,y,w,h;
  527. BOOL depress;
  528. {
  529.    w--;  h--;
  530.    if (depress)
  531.       SetAPen(rast_port,WHITE);
  532.    else
  533.       SetAPen(rast_port,BLACK);
  534.    Move(rast_port,x+w,y);
  535.    Draw(rast_port,x+w,y+h);
  536.    Draw(rast_port,x,y+h);
  537.    if (depress)
  538.       SetAPen(rast_port,BLACK);
  539.    else
  540.       SetAPen(rast_port,WHITE);
  541.    Move(rast_port,x+w,y);
  542.    Draw(rast_port,x,y);
  543.    Draw(rast_port,x,y+h);
  544. }
  545.  
  546.  
  547. // draw a 3-D look frame, to indicate if a gadget is editable
  548.  
  549. void bevel_frame(x,y,w,h,depress)
  550. int x,y,w,h;
  551. BOOL depress;
  552. {
  553.    bevel_box(x,y,w,h,depress);
  554.    bevel_box(x+1,y+1,w-2,h-2,!depress);
  555. }
  556.  
  557.  
  558. void box(x,y,w,h,color)
  559. int x,y,w,h,color;
  560. {  // draw a box
  561.    w--;  h--;
  562.  
  563.    SetAPen(rast_port,color);
  564.    Move(rast_port,x,y);
  565.    Draw(rast_port,x,y+h);
  566.    Draw(rast_port,x+w,y+h);
  567.    Draw(rast_port,x+w,y);
  568.    Draw(rast_port,x,y);
  569. }
  570.  
  571.  
  572. void frame(x,y,w,h,depress)
  573. int x,y,w,h;
  574. BOOL depress;
  575. {
  576.    w--;  h--;
  577.    if (depress) {
  578.       box(x,y,w,h,BLACK);
  579.       box(x+1,y+1,w,h,WHITE);
  580.    } else {
  581.       box(x,y,w,h,WHITE);
  582.       box(x+1,y+1,w,h,BLACK);
  583.    FI
  584. }
  585.  
  586.  
  587. void plot_text(x,y,string,frontpen,backpen,drawmode,font)
  588. int x,y;
  589. char *string;
  590. int frontpen,backpen,drawmode;
  591. struct TextAttr *font;
  592. {
  593.    struct IntuiText itext;
  594.  
  595.    itext.FrontPen = (UBYTE)frontpen;
  596.    itext.BackPen = (UBYTE)backpen;
  597.    itext.DrawMode = (UBYTE)drawmode;
  598.    itext.LeftEdge = 0;
  599.    itext.TopEdge = 0;
  600.    itext.ITextFont = font;
  601.    itext.IText = string;
  602.    itext.NextText = NULL;
  603.  
  604.    PrintIText(rast_port,&itext,x,y);
  605. }
  606.  
  607.  
  608. void outline_text(x,y,string,color,font)
  609. int x,y;
  610. char *string;
  611. int color;
  612. struct TextAttr *font;
  613. {
  614.    int ctr1, ctr2;
  615.  
  616.    for (ctr1=-1; ctr1<2; ctr1++)
  617.       for (ctr2=-1; ctr2<2; ctr2++)
  618.          plot_text(x+ctr1,y+ctr2,string,BLACK,LT_GRAY,JAM1,font);
  619.    plot_text(x,y,string,color,LT_GRAY,JAM1,font);
  620. }
  621.  
  622.  
  623. // functions to plot mines onto the screen
  624.  
  625. void px_plot_landmine(destx,desty)
  626. int destx,desty;
  627. {
  628.    // blit the image of the mine into hex_transfer
  629.    BltBitMap(&grafx_bitmap,295,156,&hex_transfer,0,0,16,8,0x0C0,0xFF,NULL);
  630.    // blit with mask from hex_transfer onto screen
  631.    BltMaskBitMapRastPort(&hex_transfer,0,0,rast_port,destx,desty,32,8,0xE0,(PLANEPTR)landmine_mask);
  632. }
  633.  
  634. void px_plot_seamine(destx,desty)
  635. int destx,desty;
  636. {
  637.    // blit the image of the mine into hex_transfer
  638.    BltBitMap(&grafx_bitmap,296,132,&hex_transfer,0,0,16,10,0x0C0,0xFF,NULL);
  639.    // blit with mask from hex_transfer onto screen
  640.    BltMaskBitMapRastPort(&hex_transfer,0,0,rast_port,destx,desty,32,10,0xE0,(PLANEPTR)seamine_mask);
  641. }
  642.  
  643.  
  644. void px_plot_icon(type,x,y,color,token,multiple)
  645. int type,x,y,color,token;
  646. BOOL multiple;
  647. {  // plot a unit icon on the map
  648.    struct icon_struct *icon = &icons[type];
  649.  
  650.    if (!icon->mask)
  651.       return;
  652.  
  653.    // step one, blit the icon
  654.    BltBitMapRastPort(&grafx_bitmap,icon->srcx,icon->srcy,rast_port,x,y,19,15,0x0C0);
  655.  
  656.    // step two, blit-fill the appropriate color
  657.    SetAPen(rast_port,color);
  658.    BltPattern(rast_port,(PLANEPTR)icon->mask,x,y,x+18,y+14,4);
  659.  
  660.    // step three, fix border as needed
  661.    bevel_box(x-1,y-1,21,17,FALSE);
  662.    if (multiple)
  663.       bevel_box(x-2,y-2,23,19,FALSE);
  664.  
  665.    // blit in the appropriate order token
  666.    if (token!=ORDER_NONE) {
  667.       int srcy=0;
  668.       switch (token) {
  669.          case ORDER_SENTRY:
  670.             srcy=66;     // S
  671.             break;
  672.          case ORDER_FORTIFY:
  673.             srcy = 114;  // orange F
  674.             break;
  675.          case ORDER_FORTIFIED:
  676.             srcy = 74;   // white F
  677.             break;
  678.          case ORDER_GOTO:
  679.             srcy = 82;   // G
  680.             break;
  681.          case ORDER_LOAD:
  682.             srcy = 106;  // L
  683.             break;
  684.          case ORDER_AIRBASE:
  685.             srcy = 122;  // orange A
  686.       }
  687.       if (srcy)
  688.          BltBitMapRastPort(&grafx_bitmap,301,srcy,rast_port,x+13,y+9,7,7,0x0C0);
  689.    }
  690. }
  691.  
  692.  
  693. void plot_icon(type,col,row,color,token,multiple)
  694. int type, col, row, color, token;
  695. BOOL multiple;
  696. {  // plot a unit icon on the map
  697.    int px, py;
  698.    struct icon_struct *icon = &icons[type];
  699.  
  700.    if (!VALID_HEX(col,row))
  701.       return;
  702.  
  703.    // icon graphic not available
  704.    if (!icon->mask)
  705.       return;
  706.  
  707.    log_to_abs(col,row,&px,&py);
  708.    px += 6;   py += 9;  // centering it in the hexagon
  709.  
  710.    px_plot_icon(type,px,py,color,token,multiple);
  711. }
  712.  
  713.  
  714.  
  715. void px_plot_city(x,y)
  716. int x,y;
  717. {
  718.    struct icon_struct *icon = &icons[CITY];
  719.    BltBitMapRastPort(&grafx_bitmap,icon->srcx,icon->srcy,rast_port,x,y,17,15,0x0C0);
  720. }
  721.  
  722. void px_plot_roads(x,y)
  723. int x,y;
  724. {
  725.    struct icon_struct *icon = &icons[ROADS];
  726.    BltBitMapRastPort(&grafx_bitmap,icon->srcx,icon->srcy,rast_port,x,y,17,15,0x0C0);
  727. }
  728.  
  729. void px_plot_city_complete(px,py,color,defended)
  730. int px,py,color;
  731. BOOL defended;
  732. {  // plot a city on the current rastport
  733.    struct icon_struct *icon = &icons[CITY];
  734.    // step one, blit the icon
  735.    BltBitMapRastPort(&grafx_bitmap,icon->srcx,icon->srcy,rast_port,px,py,17,15,0x0C0);
  736.    if (color!=0) {
  737.       SetAPen(rast_port,color);
  738.       BltPattern(rast_port,(PLANEPTR)icon->mask,px,py,px+18,py+14,4);
  739.       bevel_box(px-1,py-1,19,17,FALSE);
  740.       if (defended)
  741.          bevel_box(px-2,py-2,21,19,FALSE);
  742.    FI
  743. }
  744.  
  745.  
  746. void plot_city(col,row,color,defended)
  747. int col,row,color;
  748. BOOL defended;
  749. {  // plot a city on the map
  750.    int px, py;
  751.  
  752.    if (!VALID_HEX(col,row))
  753.       return;
  754.    if (!visibleP(col,row))
  755.       return;
  756.  
  757.    log_to_abs(col,row,&px,&py);
  758.    px += 7;    py += 9;    // center it in the hexagon
  759.    px_plot_city_complete(px,py,color,defended);
  760. }
  761.  
  762.  
  763. void save_hex_graphics(col,row,buf)
  764. int col,row,buf;
  765. {  // store a hex background to a safe place in the bitmap
  766.    // find the location
  767.    int px, py, locy;
  768.  
  769.    log_to_abs(col,row,&px,&py);
  770.    px += 5;    py += 8;    // to get the hex interior
  771.  
  772.    locy = 190+(buf*31);    // find the buffer location in my master bitmap
  773.  
  774.    // blit the background to a safe place
  775.    BltBitMap(rast_port->BitMap,px-1,py+13,&grafx_bitmap,locy,130,23,19,0x0C0,0xFF,NULL);
  776. }
  777.  
  778.  
  779. void restore_hex_graphics(col,row,buf)
  780. int col,row,buf;
  781. {
  782.    // find the location
  783.    int px, py, locy;
  784.  
  785.    log_to_abs(col,row,&px,&py);
  786.    px += 5;    py += 8;
  787.  
  788.    locy = 190+(buf*31);    // this finds the correct buffer location in my bitmap
  789.  
  790.    // restore the previously saved background
  791.    BltBitMapRastPort(&grafx_bitmap,locy,130,rast_port,px-1,py-1,23,19,0x0C0);
  792. }
  793.  
  794.  
  795. void plot_mapobject(col,row,srcx,srcy)
  796. int col,row,srcx,srcy;
  797. {
  798.    // find the location
  799.    int px, py;
  800.  
  801.    if (!VALID_HEX(col,row))
  802.       return;
  803.  
  804.    log_to_abs(col,row,&px,&py);
  805.    px += 5;    py += 8;
  806.  
  807.    // blit the cursor into place
  808.    BltBitMapRastPort(&grafx_bitmap,srcx,srcy,rast_port,px,py,21,17,0x0C0);
  809. }
  810.  
  811.  
  812. void init_map_grafx()
  813. {  // get all the internal graphics structures set up
  814.    static struct Rectangle clip_rect = { 6, 15, 617, 370 };
  815.  
  816.    // here I set window-adaptive values for my clipping rectangle
  817.    clip_rect.MinX = map_window->BorderLeft+2+10;  // 10 to make room for bar
  818.    clip_rect.MinY = map_window->BorderTop+1;
  819.    clip_rect.MaxX = map_window->Width-map_window->BorderRight-19;
  820.    clip_rect.MaxY = map_window->Height-map_window->BorderBottom-14;
  821.  
  822.    /*
  823.       This first bitmap is the big one that holds all my map graphic
  824.       elements, such as hex terrain, icon markers, and anything else
  825.       I might want to use.  It provides my link into the map_grafx.c data
  826.       prepared and compiled elsewhere.
  827.    */
  828.    InitBitMap(&grafx_bitmap,4,320,200);
  829.    grafx_bitmap.Planes[0] = (PLANEPTR)map_grafx;
  830.    grafx_bitmap.Planes[1] = (PLANEPTR)map_grafx+8000;
  831.    grafx_bitmap.Planes[2] = (PLANEPTR)map_grafx+16000;
  832.    grafx_bitmap.Planes[3] = (PLANEPTR)map_grafx+24000;
  833.  
  834.    /*
  835.       This small (32x32) bitmap is used as a temporary storage area for
  836.       blitting my hex terrain onto the map.  For some reason the Amiga
  837.       requires this roundabout way of doing things.  I don't know why.
  838.    */
  839.    InitBitMap(&hex_transfer,4,32,32);
  840.    hex_transfer.Planes[0] = (PLANEPTR)transfer_bitmap;
  841.    hex_transfer.Planes[1] = (PLANEPTR)transfer_bitmap+128;
  842.    hex_transfer.Planes[2] = (PLANEPTR)transfer_bitmap+256;
  843.    hex_transfer.Planes[3] = (PLANEPTR)transfer_bitmap+384;
  844.  
  845.    DrawBevelBox(map_window->RPort,map_window->BorderLeft,map_window->BorderTop,
  846.       map_window->Width-map_window->BorderLeft-map_window->BorderRight-16,
  847.       map_window->Height-map_window->BorderTop-map_window->BorderBottom-12,
  848.       GT_VisualInfo,vi,TAG_END);
  849.  
  850.    // now attempt to set up a clipping region for my map
  851.    map_region = NewRegion();
  852.    OrRectRegion(map_region,&clip_rect);  // add the rectangle to the region
  853.    InstallClipRegion(map_window->WLayer,map_region);
  854.  
  855.    // create also a clipping region for my movement meter bar
  856.    clip_rect.MinX = map_window->BorderLeft+2;
  857.    clip_rect.MinY = map_window->BorderTop+1;
  858.    clip_rect.MaxX = clip_rect.MinX+9;  // bar width 10 pixels
  859.    clip_rect.MaxY = map_window->Height-map_window->BorderBottom-14;
  860.    bar_region = NewRegion();
  861.    OrRectRegion(bar_region,&clip_rect);  // add the rectangle to the region
  862.  
  863.    init_icons();
  864. }
  865.  
  866.  
  867. // if there's no map being displayed, I will reset the scrollers to
  868. // full size, so they can't be moved
  869.  
  870. void zero_scrollers()
  871. {
  872.    GT_SetGadgetAttrs(horz_scroller,map_window,NULL,
  873.       GTSC_Top,      0,
  874.       GTSC_Total,    disp_wd,
  875.       GTSC_Visible,  disp_wd,
  876.       TAG_END);
  877.    GT_SetGadgetAttrs(vert_scroller,map_window,NULL,
  878.       GTSC_Top,      0,
  879.       GTSC_Total,    disp_ht,
  880.       GTSC_Visible,  disp_ht,
  881.       TAG_END);
  882. }
  883.  
  884. // update the size and position of the scroller gadgets to match
  885. // the current size and position of the game map
  886.  
  887. void update_scrollers()
  888. {
  889.    GT_SetGadgetAttrs(horz_scroller,map_window,NULL,
  890.       GTSC_Top,      xoffs + (wrap ? WRAP_OVERLAP : 0),
  891.       GTSC_Total,    width+2+2*(wrap ? WRAP_OVERLAP : 0),
  892.       GTSC_Visible,  disp_wd,
  893.       TAG_END);
  894.    GT_SetGadgetAttrs(vert_scroller,map_window,NULL,
  895.       GTSC_Top,      yoffs+(wrap ? WRAP_OVERLAP : 0),
  896.       GTSC_Total,    height+2+2*(wrap ? WRAP_OVERLAP : 0),
  897.       GTSC_Visible,  disp_ht,
  898.       TAG_END);
  899. }
  900.  
  901.  
  902. /*
  903.    Check the scrolly gadgets (presumably after one has been used)
  904.    and update the xoffs and yoffs values to match.
  905.  
  906.    If the map position has been changed, scrolly() will return a
  907.    TRUE value, otherwise FALSE.  If TRUE, the function must be followed
  908.    by appropriate activity to update the screen display.
  909. */
  910.  
  911. BOOL scrolly(object,code)
  912. struct Gadget *object;
  913. UWORD code;
  914. {
  915.    int pos=code-(wrap?WRAP_OVERLAP:0);
  916.  
  917.    if (object==horz_scroller)
  918.       if (xoffs==pos)
  919.          return FALSE;
  920.       else {
  921.          xoffs = pos;
  922.          return TRUE;
  923.       FI
  924.    else
  925.       if (yoffs==pos)
  926.          return FALSE;
  927.       else {
  928.          yoffs = pos;
  929.          return TRUE;
  930.       FI
  931. }
  932.  
  933.  
  934.  
  935. /*
  936.    fat_plot() plots a "fat" pixel onto a rastport, using the current
  937.    pen color.  This is used for the world map display.  It allows plotting
  938.    different sized pixels (i.e. fatness), in order to best fit various
  939.    size maps to the available display area.
  940. */
  941.  
  942. void fat_plot(rastport,x,y,fatness)
  943. struct RastPort *rastport;
  944. int x, y, fatness;
  945. {  // plot a "fatness" size pixel on the screen
  946.    if (fatness==1) {
  947.       WritePixel(rastport,x,y);
  948.       return;
  949.    FI
  950.    RectFill(rastport,x,y,x+fatness-1,y+fatness-1);
  951. }
  952.  
  953.  
  954. /*
  955.    visible_stripP() determines whether a certain LOGICAL sector currently
  956.    falls within a certain PHYSICAL area on the screen display.  This is
  957.    important for the optimized scrolling functions.
  958. */
  959.  
  960. BOOL visible_stripP(col,row,xmin,ymin,xmax,ymax)
  961. {  // does this sector fall within the specified strip on display?
  962.    int phx, phy;  // pysical sector coordinates
  963.  
  964.    wrap_coords(&col,&row);
  965.    phx=col-xoffs;    phy=row=yoffs;
  966.  
  967.    // correct values for wrap, if it's active
  968.    if (wrap) {
  969.       if (phx<-1)
  970.          phx += width;
  971.       if (phx>(disp_wd+1))
  972.          phx -= width;
  973.       if (phy<-1)
  974.          phy += height;
  975.       if (phy>(disp_ht+1))
  976.          phy -= height;
  977.    }
  978.  
  979.    if (phx<xmin || phx>xmax || phy<ymin || phy>ymax)
  980.       return FALSE;
  981.    else
  982.       return TRUE;
  983. }
  984.  
  985.  
  986. // within_areaP(), similar to visible_stripP(), except everything's logical
  987.  
  988. BOOL within_areaP(col,row,xmin,ymin,xmax,ymax)
  989. {  // does this sector fall within the specified area on the map?
  990.    // correct values for wrap, if it's active
  991.    if (wrap) {
  992.       if (col<xmin)
  993.          col += width;
  994.       if (col>xmax)
  995.          col -= width;
  996.       if (row<ymin)
  997.          row += height;
  998.       if (row>ymax)
  999.          row -= height;
  1000.    FI
  1001.    if (col<xmin || col>xmax || row<ymin || row>ymax)
  1002.       return FALSE;
  1003.    else
  1004.       return TRUE;
  1005. }
  1006.  
  1007.  
  1008. // visibleP() determines if a specified LOGICAL sector is on the part of
  1009. // the map currently visible in the window
  1010.  
  1011. BOOL visibleP(col,row)
  1012. int col,row;
  1013. {  // is this part of the map currently visible?
  1014.    /*
  1015.       Because of overlap, there are four possible zones that could be visible
  1016.       on the display.  I must determine which of the zones are present and
  1017.       whether the specified sector falls into one of them.
  1018.                                              ____________
  1019.                                              |       |  |<- display
  1020.                         _____________________|_______|__|
  1021.                         |  |                 |       |  |
  1022.                         | B|                 |   A   |  |
  1023.                         |__|                 |_______|__|
  1024.                         |                            |
  1025.                         |       map                  |
  1026.                         |                            |
  1027.                         |__                   _______|
  1028.                         | D|                 |   C   |
  1029.                         |__|_________________|_______|
  1030.  
  1031.  
  1032.       The large "map" box represents the logical map area.  The smaller
  1033.       box at the upper right represents the actual display.  Thanks to
  1034.       the wrap-around overlap, an area in each corner of the map is
  1035.       visible on the display.  These are categorized as follows:
  1036.  
  1037.       A = The area normally enclosed by the display.  This zone is always
  1038.           present, and is the *only* zone present when wrap is off.
  1039.  
  1040.       B = The area revealed by the horizontal wrap of the display.  This
  1041.           zone is present when xoffs<0 or xoffs+disp_wd>width.
  1042.  
  1043.       C = The area revealed by the vertical wrap of the display.  This is
  1044.           present when yoffs<0 or yoffs+disp_ht>height.
  1045.  
  1046.       D = The area revealed by both horizontal and vertical wrap.  This
  1047.           zone is present when both B and C are present.
  1048.  
  1049.       Whenever the wrap flag is active, each of these zones must be checked
  1050.       to see if it contains the specified sector.
  1051.  
  1052.       ADDENDUM: Forget about the chart and all that stuff I wrote above!
  1053.                 I figured out an easier way.  BTW, compare this to the
  1054.                 calculation of damage areas in GP_smart_scroll()!
  1055.    */
  1056.    int phx, phy;     // physical sector coordinates
  1057.  
  1058.    if (!VALID_HEX(col,row))
  1059.       return FALSE;
  1060.  
  1061.    phx = col-xoffs;
  1062.    phy = row-yoffs;
  1063.    if (wrap) {
  1064.       if (phx<0)
  1065.          phx += width;
  1066.       if (phx>disp_wd)
  1067.          phx -= width;
  1068.       if (phy<0)
  1069.          phy += height;
  1070.       if (phy>disp_ht)
  1071.          phy -= height;
  1072.    FI
  1073.    return within_areaP(phx,phy,-1,-1,disp_wd,disp_ht);
  1074. }
  1075.  
  1076.  
  1077. BOOL easily_visibleP(col,row)
  1078. {
  1079.    int phx, phy;     // physical sector coordinates
  1080.  
  1081.    phx = col-xoffs;
  1082.    phy = row-yoffs;
  1083.    if (wrap) {
  1084.       if (phx<0)
  1085.          phx += width;
  1086.       if (phx>disp_wd)
  1087.          phx -= width;
  1088.       if (phy<0)
  1089.          phy += height;
  1090.       if (phy>disp_ht)
  1091.          phy -= height;
  1092.    FI
  1093.    return within_areaP(phx,phy,1,1,disp_wd-1,disp_ht-1);
  1094. }
  1095.  
  1096.  
  1097. // The need_to_scrollP() function takes a coordinate set and
  1098. // determines whether the map needs to be scrolled to
  1099. // keep the action easily visible on screen.  This could be used when moving
  1100. // a unit on the map, or when switching from one unit to the next.
  1101.  
  1102. BOOL need_to_scrollP(xdest,ydest)
  1103. int xdest, ydest;
  1104. {
  1105.    BOOL scroll = FALSE;
  1106.  
  1107.    // first, test for the need to scroll left
  1108.    if (xoffs>0 && xdest<=(xoffs+1))
  1109.          scroll = TRUE;
  1110.  
  1111.    // test for need to scroll right
  1112.    if (xoffs<(width-disp_wd) && xdest>=(xoffs+disp_wd-2))
  1113.          scroll = TRUE;
  1114.  
  1115.    // test for need to scroll up
  1116.    if (yoffs>0 && ydest<=(yoffs+1))
  1117.          scroll = TRUE;
  1118.  
  1119.    // test for need to scroll down
  1120.    if (yoffs<(height-disp_ht) && ydest>=(yoffs+disp_ht-2))
  1121.          scroll = TRUE;
  1122.  
  1123.    return scroll;
  1124. }
  1125.  
  1126.  
  1127. // function to clear the graphics bar to black
  1128.  
  1129. void clear_movebar()
  1130. {
  1131.    if (map_window==NULL || bar_region==NULL || map_region==NULL)
  1132.       return;
  1133.    InstallClipRegion(map_window->WLayer,bar_region);
  1134.    SetRast(rast_port,BLACK);
  1135.    InstallClipRegion(map_window->WLayer,map_region);
  1136. }
  1137.  
  1138.  
  1139. // do animated movement of a unit on the map
  1140.  
  1141. void anim_move(unit,org_col,org_row,dest_col,dest_row)
  1142. struct Unit *unit;
  1143. int org_col, org_row, dest_col, dest_row;
  1144. {
  1145.    int orgx, orgy, destx, desty, ctr;
  1146.    int iter=6;    // control number of movement frames
  1147.  
  1148.    log_to_abs(org_col,org_row,&orgx,&orgy);
  1149.    orgx+=5;    orgy+=8;    // to get the hex interior
  1150.    log_to_abs(dest_col,dest_row,&destx,&desty);
  1151.    destx+=5;   desty+=8;
  1152.  
  1153.    for (ctr=0; ctr<iter; ctr++) {
  1154.       int curx, cury;
  1155.       curx = orgx+(destx-orgx)*ctr/iter;
  1156.       cury = orgy+(desty-orgy)*ctr/iter;
  1157.  
  1158.       // then draw in the icon itself
  1159.       px_plot_icon(unit->type,curx,cury,roster[unit->owner].color,NULL,NULL);
  1160.  
  1161.       // time delay for frame visibility
  1162.       if (ctr % 2)
  1163.          Delay(1L);
  1164.    OD
  1165. }
  1166.  
  1167.  
  1168.  
  1169. // end of listing
  1170.